package main

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"
)

type Server struct {
	Ip   string
	Port int
	//保存在线用户列表的 channel
	OnlineMap map[string]*User
	//对共享变量map的锁
	mapLock sync.RWMutex
	//广播群聊channel
	MessageChannel chan string
}

//创建一个Server的接口
func NewServer(ip string, port int) *Server {
	//首先相当于new 一个 Server
	//然后再取地址 & 返回内存地址 用指针返回接收
	//指针嘛 就是 指向Server类型的地址
	server := &Server{
		Ip:             ip,
		Port:           port,
		OnlineMap:      make(map[string]*User),
		MessageChannel: make(chan string),
	}
	return server
}

//监听Message广播消息channel的goroutine，一旦有消息就发送给全部的在线User
func (this *Server) ListenMessage() {
	for {
		//获得通道中的消息，会阻塞，那么通道中的 消息哪里来的？ 从 BroadCast() 函数中获得
		msg := <-this.MessageChannel
		//go锁原理是什么？有什么缺点？优点吗？
		this.mapLock.Lock()
		//遍历map 将msg发送给全部的在线User
		for _, cli := range this.OnlineMap {
			//向客户端的协程 填送消息 ，填送消息之后呢？
			cli.Channel <- msg
		}
		this.mapLock.Unlock()
	}
}

//处理连接handler  处理从 con 中获取的数据流 并通信发送给各个协程中的 channel 通道
func (this *Server) Handler(conn net.Conn) {
	//...当前链接的业务
	fmt.Println("链接建立成功")

	//新建用户
	newUser := NewUser(conn, this)

	//上线
	newUser.Online()

	//监听用户是否活跃的channel
	isLive := make(chan bool)

	//接受客户端发送的消息
	go func() {
		b := make([]byte, 4096)
		for true {
			read, err := conn.Read(b)
			if read == 0 {
				//下线
				newUser.Offline()
				return
			}
			if err != nil && err != io.EOF {
				fmt.Println("Conn Read Error,", err)
				return
			}
			//提取用户的消息(去除'\n') 暂时没有必要去除
			msg := string(b[0:read])

			//用户针对msg进行消息处理
			newUser.DoMessage(msg)

			//不断的表示用户在线
			isLive <- true
		}
	}()

	//使当前handler阻塞  不让其死亡
	for {
		//定时器功能
		//作用以及原理?
		select {
		//触发 啥也不干
		case <-isLive:
			//当前用户是活跃的，应该重置定时器
			//不做任何事情，为了激活select，更新下面的定时器 6000秒掉线
		case <-time.After(time.Second * 6000):
			//已经超时
			//将当前的User强制的关闭
			newUser.SendMsg(newUser.Name + " 你被踢了 ")

			//销毁用的资源
			close(newUser.Channel)

			//关闭连接
			conn.Close()

			//退出当前Handler
			return //runtime.Goexit()
		}
	}
}

//广播消息接口
func (this *Server) BroadCast(user *User, msg string) {
	sendMsg := "[" + user.Adder + "]" + user.Name + ":" + msg
	//这里向服务器中的 channel 填送数据处
	this.MessageChannel <- sendMsg
}

//弃用
//处理连接handler
func (this *Server) ServerHandler(conn net.Conn) {
	defer fmt.Printf("连接断开：%s\n", conn.RemoteAddr().String())
	fmt.Printf("建立连接成功：%s\n", conn.RemoteAddr().String())
	//var b []byte
	b := []byte{}
	for {
		read, err := conn.Read(b)
		if err != nil {
			fmt.Printf("读取出错\n", err)
		}
		if read > 0 {
			fmt.Printf("%s\n", string(b[:]))
		} else {
			time.Sleep(2 * time.Second)
			fmt.Println("正在尝试读取数据")
		}
	}
}

//启动服务器的家口
func (this *Server) Start() {
	//监听地址
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.Ip, this.Port))
	if err != nil {
		fmt.Println("启动Server出现错误")
		return
	}
	//close listen socket
	//马虎之处
	defer listener.Close()

	//启动监听Message的goroutine
	go this.ListenMessage()
	fmt.Println("服务器启动成功...")
	for {
		//accept 循环接收客户端请求 连接
		con, err := listener.Accept()
		if err != nil {
			fmt.Println("Server accept 出现错误", err)
			continue
		}
		//goroutine 处理读写请求
		go this.Handler(con)
	}

}
